/*
    异步日志器的缓冲区类实现
*/

#ifndef __M_BUFFER_H__
#define __M_BUFFER_H__

#include <iostream>
#include <string>
#include <vector>
#include <cassert>

namespace mylog{
    class Buffer{
        static const size_t BUFFER_SIZE = 1024 * 1;
        static const size_t THRESHOLD_SIZE = 1024 * 8;
        static const size_t INCREMEAT_SIZE = 1024 * 1;

    public:
        Buffer()
        :_buffer(BUFFER_SIZE),
        _read_idx(0),
        _write_idx(0)
        {}

        // 向缓冲区写入格式化后的日志消息
        void push(const char *data, size_t len){
            // 是否需要扩容由工作器的安全模式决定
            while(_write_idx + len > _buffer.size()){
                Expansion();
            }
            // 写入缓冲区
            std::copy(data, data + len, &_buffer[_write_idx]);
            // 移动写指针
            MoveWrite(len);
        }   
        // 获取可读数据的起始地址
        const char* ReadBegin(){
            return &_buffer[_read_idx];
        }
        // 获取可读数据的大小
        const size_t ReadSize(){
            // 注意事项：该大小在循环读取后每次获取 是逐次递减动态变化的 所以不能用来当作原始数据的大小
            return _write_idx - _read_idx;
        }
        // 移动读指针
        void MoveRead(const size_t len){
            assert(len <= ReadSize());
            _read_idx += len;
        }
        // 获取可写数据的大小
        const size_t WriteSize(){
            return _buffer.size() - _write_idx;
        }
        // 重置两个指针
        void ReSet(){
            _read_idx = 0;
            _write_idx = 0;
        }
        // 判断缓冲区是否为空
        bool Empty(){
            return _read_idx == _write_idx;
        }
        // 交换缓冲区
        bool SwapBuffer(Buffer &buffer){
            // 错误点一:判断为空的应该是参数传过来的缓冲区 而不是被调用缓冲区是否为空
            if(!buffer.Empty()){
                _buffer.swap(buffer._buffer);
                std::swap(_read_idx, buffer._read_idx);
                // 错误点二:没有交换两个缓冲区的写指针
                std::swap(_write_idx, buffer._write_idx);
                return true;
            }
            return false;
        }

    private:
        // 移动写指针
        void MoveWrite(const size_t len){
            assert(len <= WriteSize());
            _write_idx += len;
        }
        // 扩容
        void Expansion(){
            size_t newsize = 0;
            // 没有超过阈值时成倍扩容
            if (_buffer.size() < THRESHOLD_SIZE){
                newsize = 2 * _buffer.size();
            }
            // 超过阈值时线性扩容
            else{
                newsize =_buffer.size() + INCREMEAT_SIZE;
            }
            _buffer.resize(newsize);
        }

    private:
        std::vector<char> _buffer;    // 缓冲区 以字节为单位的数组
        size_t _read_idx;             // 可读数据起始地址
        size_t _write_idx;            // 可写数据起始地址
    };
}

#endif